package org.apache.ibatis.config.builder;

import org.apache.ibatis.common.type.JdbcType;
import org.apache.ibatis.common.type.TypeAliasRegistry;
import org.apache.ibatis.common.type.TypeHandler;
import org.apache.ibatis.common.type.TypeHandlerRegistry;
import org.apache.ibatis.config.mapping.ParameterMode;
import org.apache.ibatis.config.mapping.ResultSetType;
import org.apache.ibatis.sql.session.Configuration;

import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @Name BaseBuilder
 * @Description: 建造者 [基类]
 * 背景知识：建造者模式
 * 我们可以为属性较多的类创建者类，一般包括两类方法：
 * - 一类是属性设置方法。这类方法一般有多个，可以接受不同的参数来设置建造者的属性；
 * - 一类是目标对象生成方法。该类方法一般只有一个，即根据目前建造者中的属性创建出一个目标对象。
 * 在需要创建复杂的对象时，建造者模式的优势将会体现得更为明显。因此，建造者模式在一些大型的系统中非常常见。
 * 描述信息：该类是所有建造者的基类，虽然被声明成一个抽象类，但是本身不含有任何的抽象方法。它作为一个工具类，为继承它的建造者提供了众多实用的方法。
 * 1）类型转化函数
 * - *ValueOf：类型转化函数，负责将输入的参数转换成指定的类型，并支持设置默认值。
 * - resolve*：字符串转枚举类型函数。
 * 2）创建类型实例函数
 * - createInstance：创建类型实例函数，根据类型别名创建类型实例。
 * - resolveTypeHandler：根据类型处理器别名返回类型处理器实例。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-19 14:28:40
 **/
public abstract class BaseBuilder {
    protected final Configuration config;
    protected final TypeAliasRegistry typeAliasRegistry;
    protected final TypeHandlerRegistry typeHandlerRegistry;

    public BaseBuilder(Configuration config) {
        this.config = config;
        this.typeAliasRegistry = this.config.getTypeAliasRegistry();
        this.typeHandlerRegistry = this.config.getTypeHandlerRegistry();
    }

    public Configuration getConfig() {
        return config;
    }

    /********************************[类型转换函数]**********************************/

    protected Boolean booleanValueOf(String value, Boolean defaultValue) {
        return value == null ? defaultValue : Boolean.valueOf(value);
    }

    protected Integer integerValueOf(String value, Integer defaultValue) {
        return value == null ? defaultValue : Integer.valueOf(value);
    }

    protected Set<String> stringSetValueOf(String value, String defaultValue) {
        value = value == null ? defaultValue : value;
        return new HashSet<>(Arrays.asList(value.split(",")));
    }

    protected JdbcType resolveJdbcType(String alias) {
        if (alias == null) return null;
        try {
            return JdbcType.valueOf(alias);
        } catch (IllegalArgumentException e) {
            String msg = "无法解析 JdbcType 枚举类型，原因：" + e;
            throw new BuilderException(msg, e);
        }
    }

    protected ResultSetType resolveResultSetType(String alias) {
        if (alias == null) return null;
        try {
            return ResultSetType.valueOf(alias);
        } catch (IllegalArgumentException e) {
            String msg = "无法解析 ResultSetType 枚举类型，原因：" + e;
            throw new BuilderException(msg, e);
        }
    }

    protected ParameterMode resolveParameterMode(String alias) {
        if (alias == null) return null;
        try {
            return ParameterMode.valueOf(alias);
        } catch (IllegalArgumentException e) {
            String msg = "无法解析 ParameterMode 枚举类型，原因：" + e;
            throw new BuilderException(msg, e);
        }
    }

    protected <T> Class<? extends T> resolveClass(String alias) {
        if (alias == null) return null;
        try {
            return resolveAlias(alias);
        } catch (Exception e) {
            String msg = "无法解析 Class 类型，原因：" + e;
            throw new BuilderException(msg, e);
        }
    }

    protected <T> Class<? extends T> resolveAlias(String alias) {
        return typeAliasRegistry.resolveAlias(alias);
    }

    /**
     * 解析扩展字段
     *
     * @param regex        正则表达式
     * @param defaultValue 默认值
     */
    protected Pattern parseExpression(String regex, String defaultValue) {
        return Pattern.compile(regex == null ? defaultValue : regex);
    }

    /********************************[创建类型实例]**********************************/

    protected Object createInstance(String alias) {
        Class<?> clazz = resolveClass(alias);
        if (clazz == null) return null;
        try {
            return resolveClass(alias).newInstance();
        } catch (Exception e) {
            String msg = "无法创建实例，原因：" + e;
            throw new BuilderException(msg, e);
        }
    }

    protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, String typeHandlerAlias) {
        if (typeHandlerAlias == null) return null;
        Class<?> type = resolveClass(typeHandlerAlias);
        if (type != null && !TypeHandler.class.isAssignableFrom(type)) {
            String msg = "类型 [" + type.getName() + "] 不是一个有效的类型处理器，因为它没有实现 TypeHandler 接口。";
            throw new BuilderException(msg);
        }
        // 忽略检查，因为已经验证它是一个 TypeHandler 类型处理器了。
        @SuppressWarnings("unchecked")
        Class<? extends TypeHandler<?>> typeHandlerType = (Class<? extends TypeHandler<?>>) type;
        return resolveTypeHandler(javaType, typeHandlerType);
    }

    protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, Class<? extends TypeHandler<?>> typeHandlerType) {
        if (typeHandlerType == null) return null;
        TypeHandler<?> handler = typeHandlerRegistry.getMappingTypeHandler(typeHandlerType);
        if (handler == null) handler = typeHandlerRegistry.getInstance(javaType, typeHandlerType);
        return handler;
    }

}

